﻿using System.IO;
using System.Web.Mvc;
using System.Linq;
using cludg.Domain.Content.Stories.Subjects;
using cludg.Domain.Environment;
using cludg.Services.Images;
using cludg.Web.Core.Utils;
using cludg.Services.Content;
using cludg.Web.Core.Controllers;
using cludg.Infrastructure.Core.Attributes;
using cludg.Web.Core.Security;
using cludg.Web.Core.Validation;
using cludg.Web.Core.ViewModels;
using cludg.Web.ViewModels;
using cludg.Domain.Content.Stories;
using cludg.Utils.Html;

namespace cludg.Web.Controllers
{
	public class StoryController : BaseController
	{
		[Dependency]
		public IStoryService StoryService { get; set; }
		[Dependency]
		public ICommentService CommentService { get; set; }
		[Dependency]
		public IOfferService OfferService { get; set; }

		#region Show
		protected virtual TModel CreateStoryDetailsModel<TModel>(Story story) where TModel : StoryDetailsModel, new()
		{
			return CreateModel<TModel>(
				delegate(TModel model)
				{
					model.Story = story;
					model.ShowComments = CurrentUserHasPermission("ViewStoryComments", story);
					model.CanAddComment = CurrentUserHasPermission("CommentStory", story);
				});
		}

		[PermissionRequierd("ViewStories")]
		public ActionResult Show(string id)
		{
			var story = StoryService.ById(id);

			if (story == null)
				return RedirectToAction("Index", "Home", null);

			var model = CreateStoryDetailsModel<StoryDetailsModel>(story);
			model.NavigationMenu.SetActiveItem("Index");

			IncViewCountInHistory(story);

			return View(model);
		}

		[PermissionRequierd("ViewStories")]
		public ActionResult ShowByName(string name)
		{
			var story = StoryService.All.FirstOrDefault(x => x.UniqueName == name);

			if (story == null)
				return RedirectToAction("Index", "Home", null);

			var model = CreateStoryDetailsModel<StoryDetailsModel>(story);
			model.NavigationMenu.SetActiveItem("Index");

			IncViewCountInHistory(story);

			return View("Show", model);
		}

		protected void IncViewCountInHistory(Story story)
		{
			HistoryService.Add(story.Id, HistoryEntryType.View, GetCurrentUserId(), Session.SessionID);
		}

		#endregion

		#region Comment
		protected virtual TModel CreateCommentModel<TModel>(string storyId, string commentId) where TModel : CommentModel, new()
		{
			return CreateModel<TModel>(
				delegate(TModel model)
				{
					model.StoryId = storyId;
					model.CommentId = commentId;
				});
		}

		/// <summary>
		/// Нужен для обеспечения работы системы комментариев при отключеном JavaScript
		/// </summary>
		/// <param name="id"></param>
		/// <param name="commentId"></param>
		/// <returns></returns>
		[PermissionRequierd("CommentStory")]
		public ActionResult Comment(string id, string commentId)
		{
			var model = CreateCommentModel<CommentModel>(id, commentId);
			if (model != null)
				model.NavigationMenu.SetActiveItem("Index");

			return View("Comment", model);
		}

		[HttpPost]
		[PermissionRequierd("CommentStory")]
		[ValidateInput(false)]
		public ActionResult Comment(CommentModel model)
		{
			var commentId = string.Empty;

			if (ModelState.IsValid)
			{
				var comment = CommentService.NewComment(model.StoryId, model.CommentId, GetCurrentUser(false),
					model.CommentBody.HtmlSantinized());
				commentId = comment.Id;
				ShowMessage(MessageType.Success, "Ваш комментарий добавлен");
			}
			else
			{
				ShowMessage(MessageType.Error, string.Format("Ошибка при добавлении комментария: {0}",
					GetModelStateErrors()));
			}

			// return to story view and set position to added comment
			return Redirect(Url.RouteUrl(new { controller = "Story", action = "Show", id = model.StoryId }) +
				(string.IsNullOrEmpty(commentId) ? "" : string.Format("#comment_{0}", commentId)));
		}

		[PermissionRequierd("ManageComment")]
		public ActionResult DeleteComment(string id)
		{
			var comment = CommentService.ById(id);
			comment.IsDeleted = true;
			comment.DeletedText = comment.Text;
			comment.Text = "<i>Удален администратором</i>";
			CommentService.UpdateComment(comment);
			ShowMessage(MessageType.Info, "Комментарий удален");

			return Redirect(Url.RouteUrl(new { controller = "Story", action = "Show", id = comment.Story.Id }) +
				(string.IsNullOrEmpty(id) ? "" : string.Format("#comment_{0}", id)));
		}

		[PermissionRequierd("ManageComment")]
		public ActionResult RestoreComment(string id)
		{
			var comment = CommentService.ById(id);
			comment.IsDeleted = false;
			comment.Text = comment.DeletedText;
			comment.DeletedText = null;
			CommentService.UpdateComment(comment);
			ShowMessage(MessageType.Info, "Комментарий восстановлен");

			return Redirect(Url.RouteUrl(new { controller = "Story", action = "Show", id = comment.Story.Id }) +
				(string.IsNullOrEmpty(id) ? "" : string.Format("#comment_{0}", id)));
		}
		
		#endregion

		#region Add
		[PermissionRequierd("AddStory")]
		public ActionResult Add()
		{
			var model = CreateModel<StoryAddModel>();
			model.NavigationMenu.SetActiveItem("AddStory");
			return View(model);
		}

		[HttpPost]
		[ValidateInput(false)]
		[PermissionRequierd("AddStory")]
		public ActionResult Add(StoryAddModel model)
		{
			InitModel(model);
			model.NavigationMenu.SetActiveItem("AddStory");
			bool imageSaveSuccess = true;

			if (!ModelState.IsValid)
			{
				return View(model);
			}

			Stream imageStream = null;
			// 1. If defined image content URL - load it to repository
			string realSizeImageId = string.Empty;
			string subjectImageId = string.Empty;
			if (!string.IsNullOrEmpty(model.ImageUrl))
			{
				// TODO: Надо проверку на размер и формат картинки до того, как скачали её
				imageStream = RequestUtils.Download(model.ImageUrl);
			}
			else
			{
				// 2. Load selected image
				if (Request.Files.Count > 0)
				{
					var contentImageFile = Request.Files[model.ImageUploadFileName];
					if (contentImageFile != null && contentImageFile.InputStream != null && contentImageFile.ContentLength > 0)
					{
						// check for image size and type
						string validationMessage;
						if (!ImageValidationUtil.ValidatePostedImageFile(contentImageFile,
							ImageValidationUtil.SubjectImageSize, out validationMessage))
						{
							imageSaveSuccess = false;
							ModelState.AddModelError(string.Empty, validationMessage);
						}
						else
						{
							imageStream = contentImageFile.InputStream;
						}
					}
					else
					{
						// Не указан ни один источник для картинки
						imageSaveSuccess = false;
						ModelState.AddModelError(string.Empty, "Необходимо указать ссылку на изображение или выбрать изображение на вашем компьютере.");
					}
				}
			}
			if (imageSaveSuccess)
			{
				using (imageStream)
				{
					if (imageStream != null)
					{
						var ids = ImageService.Add(imageStream, new[] { ImageSize.Real, ImageSize.ImageSubject }, true);
						realSizeImageId = ids[0];
						subjectImageId = ids[1];
					}
				}

				var subject = new ImageSubject { RealSizeImageId = realSizeImageId, SubjectImageId = subjectImageId };
				var currentUser = GetCurrentUser(false);
				var story = StoryService.NewStory(
					subject,
					currentUser,
					currentUser,
					model.Title,
					model.Body.HtmlSantinized(),
					model.AnonymouseAuthorName,
					model.Tags);

				ShowMessage(MessageType.Info, "История успешно добавлена");

				return RedirectToRoute("Story", new { name = story.UniqueName });
			}

			return View("Add", model);
		}

		#endregion

		#region Delete
		public ActionResult Delete(string id)
		{
			var story = StoryService.ById(id);

			if (story == null)
			{
				ShowMessage(MessageType.Error, string.Format("История {0} не найдена", id));
				return RedirectToAction("Index", "Home");
			}

			ActionResult errorResult;
			if (!CheckAccessDenied("DeleteStory", story, out errorResult))
				return errorResult;

			var model = CreateModel<ConfirmDeleteStoryModel>(
				delegate(ConfirmDeleteStoryModel m)
				{
					m.Story = story;
				});

			return View("ConfirmDelete", model);
		}

		[HttpPost]
		public ActionResult Delete(DeleteStoryModel model)
		{
			var story = StoryService.ById(model.StoryId);

			if (story == null)
			{
				ShowMessage(MessageType.Error, string.Format("История {0} не найдена", model.StoryId));
				return RedirectToAction("Index", "Home");
			}

			ActionResult errorResult;
			if (!CheckAccessDenied("DeleteStory", story, out errorResult))
				return errorResult;

			StoryService.DeleteStory(story);

			ShowMessage(MessageType.Success, "История удалена");
			return RedirectToAction("Index", "Home");
		}
		#endregion

		#region Edit
		public ActionResult Edit(string id)
		{
			var story = StoryService.ById(id);

			if (story == null)
			{
				ShowMessage(MessageType.Error, string.Format("История {0} не найдена", id));
				return RedirectToAction("Index", "Home");
			}

			ActionResult errorResult;
			if (!CheckAccessDenied("EditStory", story, out errorResult))
				return errorResult;

			var model = CreateModel<StoryEditModel>(
				delegate(StoryEditModel m)
				{
					m.Story = story;
					m.Title = story.Title;
					m.Body = story.Body;
					m.Tags = story.GetTagsAsString(',');
				});

			return View("Edit", model);
		}

		[HttpPost]
		[ValidateInput(false)]
		public ActionResult Edit(StoryEditedModel model)
		{
			InitModel(model);

			var story = StoryService.ById(model.StoryId);

			if (story == null)
			{
				ShowMessage(MessageType.Error, string.Format("История {0} не найдена", model.StoryId));
				return RedirectToAction("Index", "Home");
			}

			ActionResult errorResult;
			if (!CheckAccessDenied("EditStory", story, out errorResult))
				return errorResult;

			if (!ModelState.IsValid)
			{
				var model2 = CreateModel<StoryEditModel>(
					delegate(StoryEditModel m)
					{
						m.Story = story;
						m.Title = story.Title;
						m.Body = story.Body;
						m.Tags = story.GetTagsAsString(','); ;
					});

				return View("Edit", model2);
			}

			StoryService.EditStory(story,
				model.Title, model.Body.HtmlSantinized(), model.Tags);

			ShowMessage(MessageType.Success, string.Format("\"{0}\" отредактировано", story.Title));

			return RedirectToRoute("Story", new { name = story.UniqueName });
		}
		#endregion
	}
}
